use super::Log;
use std::{collections::BTreeMap, error::Error};

#[derive(Debug)]
pub struct BitCash {
    pub log: Log,
    pub cache: BTreeMap<Vec<u8>, u64>,
}

impl BitCash {
    pub fn new(path: &str, name: &str) -> Self {
        let log = Log::new(path, name);
        BitCash {
            log,
            cache: BTreeMap::new(),
        }
    }

    pub fn write(&mut self, key: &Vec<u8>, value: &Vec<u8>) -> Result<(), Box<dyn Error>> {
        let pos = self.log.write(key, value)?;
        self.cache.insert(key.clone(), pos);
        Ok(())
    }

    pub fn read(&self, key: &Vec<u8>) -> Result<(Vec<u8>, Option<Vec<u8>>), Box<dyn Error>> {
        let key_pos = self.cache.get(key);
        match key_pos {
            Some(&pos) => self.log.read(pos),
            None => Ok((key.clone(), None)),
        }
    }
}

#[cfg(test)]
mod test {

    use std::error::Error;

    use super::BitCash;

    #[test]
    fn test() -> Result<(), Box<dyn Error>> {
        let mut bitcach = BitCash::new("/tmp/rust-db/", "db.log");
        bitcach.write(
            &bincode::serialize("hello").unwrap(),
            &bincode::serialize("world").unwrap(),
        )?;
        bitcach.write(
            &bincode::serialize("hi").unwrap(),
            &bincode::serialize("rust").unwrap(),
        )?;
        bitcach.write(
            &bincode::serialize("hello").unwrap(),
            &bincode::serialize("hello rust").unwrap(),
        )?;

        let (key, value_option) = bitcach.read(&bincode::serialize("hi").unwrap())?;
        println!(
            "key: {:#?}, value: {:#?}",
            bincode::deserialize::<String>(&key),
            bincode::deserialize::<String>(&value_option.unwrap())
        );

        Ok(())
    }
}
